#!/usr/bin/perl
use warnings;
use strict;

#formato de cada linea del listado, los datos a imprimir son:
# BENEFICIO AGENCIA CUIL APELLIDO PROVINCIA ESTADO FECHA ALTA
my $formatoSalida = "| %-5.5s | %-6.6s | %-11.11s | %-20.20s | %-20.20s | %1.1s | %10.10s |";

sub MostrarAyudaCompleta{
print <<HELP
USO:
$0 -f nombrearchivos -a agencias -b beneficios [-t|-d|-td|-dt] [-c [-ea -ep -er]]

opcion  descripcion

-f      files:
        nombre del archivo de origen de datos de los beneficiarios.
        pude ser el nombre de un solo archivo, una lista de archivos
        separadas por espacio , tambien una lista expresada por un
        nombre y un comodin o todos los archivos.
        ejemplos:
        -f benef.001
        -f benef.001 benef.003 benef.005
        -f benef.02*
        -f *

-a      agencias:
        Esta opcion permite filtrar las agencias que se van a usar
        para generar el listado.  Acepta como parametros el codigo
        de una agencia, una lista de codigos (separados por espacio) o
        todas las agencias (usando *)
        ejemplos:
        -a 001056
        -a 000123 000506 010034
        -a "*"

-b      beneficios:
        Esta opcion permite filtrar los beneficios que se van a usar
        para generar el listado.  Acepta como parametros el codigo
        de un beneficios, una lista de codigos beneficios
        (separados por espacio) o todas los beneficios (usando *)
        ejemplos:
        -b 001056
        -b 000123 000506 010034
        -b "*"
-c	matriz de control:
	Esta opcion genera una matriz con los totales por provincias y 
	por beneficios.  Las provincias estan representadas por las filas
	de la matriz y los beneficios por las columnas.
	
	Cuando se utiliza esta opcion, se pueden usar 3 opciones de filtro
 	de datos segun el estado del beneficio.  Estas son:
	-ea : solo muestra los beneficios que se encuentran aprobados.
	-ep : solo muestra los beneficios que se encuentran pendientes.
	-er : solo muestra los beneficios que se encuentran rechazados.

	Estas opciones se pueden usar en forma combinada para obtener 
	los beneficios que se encuentran en mas de un estado. 
	Por ej:
	-ea -ep : muestra los beneficios que se encuentra aprobados y 
 	tambien los que estan pendientes de aprobacion.

-t	Emite el listado por salida standar 

-d	Emite el listado en un archivo.  El archivo salida estara ubicado
	en \$grupo/list y tendra por nombre plist.XXXXXX donde XXXXXX son digitos
	que mantienen la secuencia de los listados emitidos.

-td 
-dt	Emite el listado tanto por salida standar como a un archivo.

Valores de Retorno:
	0:El programa se ejecuto correctamente.
	1:El programa no se pudo ejecutar porque no estan seteadas las variables
	  de ambiente necesarias.
	2:Los parametros para la ejecucion no son correctos
HELP
}

sub MostrarAyudaRapida(){
	my $WORKINGDIR='';
	print "USO: \n$0 -f archivos -a agencias -b beneficios [-t|-d|-td|-dt] [-c [-ea -ep -er]]\n";
	print "Para mas ayuda $0 -h\n";
}

sub ErrorLineaComandos(){
	&LoggearMensaje("E","Linea de comando invalida\n");
	print "ERROR: Linea de comando invalida\n";
	&MostrarAyudaRapida();
}

sub LoggearMensaje(){
	my ($tipo, $mensaje) = @_;
	chomp($mensaje);
	#my $programa = "$0";
	my $programa = "plist";
	my $logger = "$ENV{'BINDIR'}/gralog.sh";
	my $result =  `$logger "$programa" "$mensaje" "$tipo"`;
	#print "***** $logger $programa $mensaje $tipo\n";

}

sub ParsearArgumentos(){
	my ($refcfg,@args)= @_;
	my $cantargs = @args;	
	if ($cantargs == 1){
		if ($args[0] eq '-h'){
			&MostrarAyudaCompleta();
			return 2;
		}else{
			&ErrorLineaComandos();
			return 1;
		}

	}
	my @files;
	my @beneficios;
	my @agencias;
	my %opciones = ( "SalidaPantalla" => 1,
			"SalidaArchivo" => 0,
			"MatrizControl" => 0,
			"FiltrarEstados" => 0,
			"MostrarAprobados" => 0,
			"MostrarRechazados" => 0,
			"MostrarPendientes" => 0
			);
			
	my $refparamtemp;
	my $cargarparam = 0;
	foreach my $arg (@args){
		if ($arg eq '-f'){
			$refparamtemp = \@files;
			$cargarparam = 1;
		}elsif ($arg eq '-a'){
			$refparamtemp = \@agencias;
			$cargarparam = 1;
		}elsif ($arg eq '-b'){
			$refparamtemp = \@beneficios;
			$cargarparam = 1;
		}elsif ($arg eq '-t'){
			$opciones{"SalidaArchivo"} = 0;
			$opciones{"SalidaPantalla"} = 1;
			$cargarparam = 0;
		}elsif ($arg eq '-d'){
			$opciones{"SalidaArchivo"} = 1;
			$opciones{"SalidaPantalla"} = 0;
			$cargarparam = 0;
		}elsif (($arg eq '-td') || ($arg eq '-dt')){
			$opciones{"SalidaArchivo"} = 1;
			$opciones{"SalidaPantalla"} = 1;
			$cargarparam = 0;
		}elsif ($arg eq '-c'){
			$opciones{"MatrizControl"} = 1;
			$opciones{"FiltrarEstados"} = 0;
			$cargarparam = 0;
		}elsif ($arg eq '-ea'){
			if ($opciones{"MatrizControl"} == 1) {
				$opciones{"FiltrarEstados"} = 1;
				$opciones{"MostrarAprobados"} = 1;
				$cargarparam = 0;
			}else{
				&ErrorLineaComandos();
				return 1;
			}
		}elsif ($arg eq '-ep'){
			if ($opciones{"MatrizControl"} == 1) {
				$opciones{"FiltrarEstados"} = 1;
				$opciones{"MostrarPendientes"} = 1;
				$cargarparam = 0;
			}else{
				&ErrorLineaComandos();
				return 1;
			}
		}elsif ($arg eq '-er'){
			if ($opciones{"MatrizControl"} == 1) {
				$opciones{"FiltrarEstados"} = 1;
				$opciones{"MostrarRechazados"} = 1;
				$cargarparam = 0;
			}else{
				&ErrorLineaComandos();
				return 1;
			}
		}elsif ($cargarparam == 1){
			push @$refparamtemp, $arg;
		}else{
			&ErrorLineaComandos();
			return 1;
		}
	}
	if ((scalar(@files) == 0) || (scalar(@beneficios) == 0) || (scalar(@agencias) == 0)){
		&ErrorLineaComandos();
		return 1;
	}
	if ($opciones{"FiltrarEstados"} == 0){
		$opciones{"MostrarAprobados"} = 1;
		$opciones{"MostrarPendientes"} = 1;
		$opciones{"MostrarRechazados"} = 1;
	}

#se copia la configuracion indicada por la linea de comando a la configuracion gral
	foreach my $k (keys %opciones){
		#print "keys: $k => $opciones{$k}\n";
		$$refcfg{$k} = $opciones{$k};
	}
	$$refcfg{"files"} = \@files;
	$$refcfg{"agencias"} = \@agencias;
	$$refcfg{"beneficios"} = \@beneficios;
	return 0;

}

sub ImprimirLinea(){
	my ($texto,@salidas) = @_;
	chomp($texto);
	foreach my $output (@salidas){
		print $output $texto;
		print $output "\n";
	}
}

sub ImprimirEncabezado(){
	my ($refargs,@salidas) = @_;
	my $fecha = `date +"%Y-%m-%d %H:%M:%S"`;
	chomp($fecha);
	&ImprimirLinea( "*"x80,@salidas);
	&ImprimirLinea( "FECHA: $fecha\n",@salidas);
	&ImprimirLinea("USUARIO: $ENV{'USER'}\n", @salidas);
	my $lineacmd = "$0 @$refargs"; 
	&ImprimirLinea("PARAMETROS: $lineacmd \n",@salidas);
	&ImprimirLinea("*"x80,@salidas);
}



#subrutina que convierte una array con los campos del archivo benef.xxx
#a un registro en formato de has  con los datos que se van a usar en el listado  
#para una referencia mas simple y legible
sub Campos2Registro(){
	my @campos = @_;
	my %reg = ();
	$reg{"beneficio"} = $campos[2];
	$reg{"agencia"} = $campos[0];
	$reg{"cuil"} = $campos[3];
	$reg{"apellido"} = $campos[6];
	$reg{"provincia"} = $campos[10];
	$reg{"estado"} = $campos[15];
	$reg{"fechaEfectivaAlta"} = $campos[12];
	return %reg;
}

sub FormatearLinea(){
	my %reg = @_;
	my @campos = ($reg{"beneficio"},$reg{"agencia"},$reg{"cuil"},$reg{"apellido"},
				$reg{"provincia"},$reg{"estado"},$reg{"fechaEfectivaAlta"});

	my $linea = sprintf( $formatoSalida, @campos);
	return $linea;
}

#Subrutina que convierte una lista en un hash para realizar consultas mas rapidas de si
#un valor se encuentra en la lista o no
sub Array2Hash(){
	my @array = @_;
	my %hash = ();
	foreach my $i (@array){
		$hash{$i} = 1;
	}	
	return %hash;
}


sub MostrarTodasAgencias(){
	my ($refcfg,@arg) = @_;
	my $refAgenciasValidas = $$refcfg{"agencias"};
	my @agencias = @$refAgenciasValidas;
	if (scalar(@agencias) >= 1){
		if ($agencias[0] eq "*"){
			return 1;
		}else{
			return 0;
		}
	}else{
		&LoggearMensaje("E","La lista de agencias a filtrar esta vacia");
		return -1;
	}
	
}
sub MostrarTodosBeneficios(){
	my ($refcfg,@arg) = @_;
	my $refBeneficiosValidos = $$refcfg{"beneficios"};
	my @a = @$refBeneficiosValidos;
	if (scalar(@a) >= 1){
		if ($a[0] eq "*"){
			return 1;
		}else{
			return 0;
		}
	}else{
		&LoggearMensaje("E","La lista de beneficios a filtrar esta vacia");
		return -1;
	}
	
}

sub CrearHashFiltroXEstado(){
	my ($refcfg,@arg) = @_;
	my %filtro = (  "A" => 1,	
			"P" => 1,
			"R" => 1
			);
	if ($$refcfg{"FiltrarEstados"} == 1){
		$filtro{"A"} = $$refcfg{"MostrarAprobados"};
		$filtro{"P"} = $$refcfg{"MostrarPendientes"};
		$filtro{"R"} = $$refcfg{"MostrarRechazados"};
	}
	return %filtro;
}



sub CargarMatriz(){
	my ($refRegistro,$refMatriz,$refTotProvincia,$refTotBeneficio,@arg) = @_;
	my $pcia = $$refRegistro{"provincia"};
	my $benef = $$refRegistro{"beneficio"};
	if (exists $$refTotProvincia{$pcia}){
		$$refTotProvincia{$pcia} += 1;
	}else{
		$$refTotProvincia{$pcia}= 1;	
	}
	if (exists $$refTotBeneficio{$benef}){
		$$refTotBeneficio{$benef} += 1;
	}else{
		$$refTotBeneficio{$benef}= 1;	
	}
	my $clave = "$pcia,$benef";
	if (exists $$refMatriz{$clave} ){
		$$refMatriz{$clave} += 1;
	}else{
		$$refMatriz{$clave} = 1;
	}
	
}


sub ImprimirMatriz(){
	my ($refMatriz, $refTotProvincias, $refTotBeneficios, @salidas) = @_;
	my @beneficios = sort keys %$refTotBeneficios;

	#Armo el encabezado de la matriz
	&ImprimirLinea(" "x80,@salidas);
	

	&ImprimirLinea("*"x80,@salidas);
	&ImprimirLinea("* Matriz de Control:",@salidas);
	&ImprimirLinea("*"x80,@salidas);
	&ImprimirLinea("* Provincia       * ".join(" * ",@beneficios)." * Totales *",@salidas);
	&ImprimirLinea("*"x80,@salidas);


	foreach my $pcia (keys %$refTotProvincias){
		my @linea = ();
		push @linea, sprintf("* %-15.15s", $pcia);

		foreach my $benef (@beneficios){
			my $clave = "$pcia,$benef";
			my $valor = 0;	
			if (exists $$refMatriz{$clave} ){
				$valor = $$refMatriz{$clave} ;
			}
			push @linea, sprintf("%5d",$valor);
			
		}
		push @linea, sprintf("%7d *" ,$$refTotProvincias{$pcia}) ;
		my $lineafmt = join " * ", @linea;
		&ImprimirLinea($lineafmt,@salidas);
	}
	my $totalTotales = 0;
	my @linea = ();
	push @linea, "* Totales        ";
	foreach my $b (@beneficios){
		push @linea, sprintf("%5d",$$refTotBeneficios{$b});
		$totalTotales += $$refTotBeneficios{$b};
	}
	push @linea, sprintf("%7d *", $totalTotales) ;
	my $lineafmt = join " * ", @linea ;
	&ImprimirLinea($lineafmt,@salidas);
	&ImprimirLinea("*"x80,@salidas);
}

sub GenerarNombreArchivoSalida(){
	my $directorio = "$ENV{'grupo'}/list";
	my @existentes = ();
	if (-d $directorio ) {
		@existentes = `ls -1 $directorio/plist*`;
		@existentes = sort @existentes;
	}else{
		`mkdir $directorio`;
	}


	
	my $ultimoNombre = "";
#	print "existentes:@existentes...\n";
	if (scalar(@existentes) > 0){
		$ultimoNombre = $existentes[$#existentes];
		chomp($ultimoNombre);
	}else{
		$ultimoNombre = "$directorio/plist.00000";
	}
#	print "ultimoNombre:$ultimoNombre...\n";
	my ($nombre,$ultimoNumero) = split (/\./, $ultimoNombre);
#	print "nombre:$nombre...\n";
#	print "nro:$ultimoNumero...\n";
	my $nuevoNumero = $ultimoNumero+1;
	return "$nombre.".sprintf("%05d",$nuevoNumero);
}

sub ProcesarArchivo(){
	my ($refhashcfg,@param) = @_;

	my $refListaFiles = $$refhashcfg{"files"};
	my @files = @$refListaFiles;

#preparo el filtro por agencias
#se usa una variable bandera para ver si se muestran todas la agencias o se realiza un filtrado
#se usa un hash para consultar si una agencia debe estar incluida en el listado o no, de acuerdo a la lista pasada por parametros
	my $verTodasAgencias = &MostrarTodasAgencias($refhashcfg);
	my %agencias = ();
	if ($verTodasAgencias == 0){
		my $refagencias = $$refhashcfg{"agencias"};
		%agencias = &Array2Hash(@$refagencias);
	}
	
#preparo el filtro por beneficios
#se usa una variable bandera para ver si se muestran todos los beneficios o se realiza un filtrado
#se usa un hash para consultar si un beneficio debe estar incluido en el listado o no, de acuerdo a la lista pasada por parametros
	my $verTodosBeneficios = &MostrarTodosBeneficios($refhashcfg);
	my %beneficios = ();
	if ($verTodosBeneficios == 0){
		my $refbenef = $$refhashcfg{"beneficios"};
		%beneficios = &Array2Hash(@$refbenef);
	}

#preparo el filtro por estados
#se usa una variable bandera para ver si se debe filtrar los estados por la creacion de la matriz de control
#se usa un hash para consular si un estado debe estar incluido en el listado o no
	my $verMatrizControl = $$refhashcfg{"MatrizControl"};
	my %estados = &CrearHashFiltroXEstado($refhashcfg);

#preparo el array de salidas sobre las cuales se tienen que emitir los resultados del procesamiento
	my @salidas = ();	
	if ($$refhashcfg{"SalidaPantalla"} == 1){
		push @salidas, \*STDOUT;
	}
	if ($$refhashcfg{"SalidaArchivo"} == 1){
		my $nombre = &GenerarNombreArchivoSalida();
		print "Salida: $nombre\n";
		open ARCHSALIDA, "> $nombre";
		push @salidas, \*ARCHSALIDA;
	}
	
#inicializo las estructuras que voy a utilizar si tengo que armar la matriz de control
#Matriz: va a ser un hash cuya clave va a ser "provincia, beneficio"
#TotalesXProvincia: va a ser un hash cuya clave va a ser la provincia y el valor van a ser la cantidad de registros procesados para
#esa provincia.  
#TotalesXBeneficio: va a ser un hash cuya clave va a ser el beneficio y el valor va  a ser la cantidad de registros procesador para
#ese beneficios
	my %Matriz = ();
	my %TotalesXProvincia =  ();
	my %TotalesXBeneficio = ();
	my $cantRegistrosListados = 0;

	&ImprimirEncabezado(\@ARGV,@salidas);

	&ImprimirLinea("-"x95,@salidas);
	my @EncabColumnas = ("BENEFICIO", "AGENCIA", "CUIL", "APELLIDO", "PROVINCIA","ESTADO","FECHA ALTA");
	my $lineaEncab = sprintf( $formatoSalida, @EncabColumnas);
	&ImprimirLinea($lineaEncab,@salidas);
	&ImprimirLinea("-"x95,@salidas);
	foreach my $entrada (@files){

		open ENTRADA, "<$entrada";
		my $nrolinea = 1;
		while (<ENTRADA>){
			my @campos = split(',',$_);
			if (scalar(@campos) == 19){
				my %registro = &Campos2Registro(@campos);

				if ($verTodasAgencias != 1 ){
					if (! exists $agencias{$registro{"agencia"}}){
						next;
					}
				}
				if ($verTodosBeneficios != 1 ){
					if (! exists $beneficios{$registro{"beneficio"}}){
						next;
					}
				}
				if ($verMatrizControl == 1){
					if ($estados{$registro{"estado"}} == 0){
						next;
					}	
					&CargarMatriz(\%registro,\%Matriz,\%TotalesXProvincia,\%TotalesXBeneficio);	
				
				}
				my $linea = &FormatearLinea(%registro);
				&ImprimirLinea($linea,@salidas);
				$cantRegistrosListados++;
			}else{
				&LoggearMensaje('E',"La linea $nrolinea del archivo $entrada tiene \
						una cantidad incorrecta de campos");
			}
		}	
		close ENTRADA;
	}

	&ImprimirLinea("-"x95,@salidas);
	&ImprimirLinea("Total de Registros Mostrados: $cantRegistrosListados",@salidas);
	if ($verMatrizControl == 1){
		&ImprimirMatriz(\%Matriz,\%TotalesXProvincia,\%TotalesXBeneficio,@salidas);
	}
	if ($$refhashcfg{"SalidaArchivo"} == 1){
		close ARCHSALIDA;
	}
}


sub ChequearAmbiente(){
	my @variablesreq = ('BINDIR', 'grupo');
	foreach my $v (@variablesreq){
		if (not exists $ENV{$v}){
			print "ERROR: Variable de entorno no existe: $v.\n";
			return 1;
		}
		if (not defined $ENV{$v}){
			print "ERROR: Variable de entorno no esta definida: $v.\n";
			return 1;
		}
	}



	foreach my $k (keys(%ENV)){
#		print "$k => $ENV{$k}\n";
	}
	return 0;
}



my %cfg = ();
my $res = 0;

$res = &ChequearAmbiente();
if ($res != 0){
	#&LoguearMensaje("E","Las variables de ambientes requeridas no estan correctamente seteadas");
	print "ERROR: Las variables de ambientes requeridas no estan correctamente seteadas\n";
	exit 1;
	
}
$res = &ParsearArgumentos(\%cfg,@ARGV);
foreach my $k (keys %cfg){
#	print "$k";
#	print " =>";
#	print " $cfg{$k}\n";
}
if ($res == 0){
	&ProcesarArchivo(\%cfg);
	exit 0;
}elsif ($res == 2){
	#se solicito la ayuda extendida, se devuelve el valor de ejecucion correcta
	exit 0;
}
exit 2;
